#include "GamePrintUtils.h"
#include "Team.h"
#include "Vectors.h"
#include "Global.h"
#include "StringUtilities.h"
#include "PrintUtilities.h"
#include "People.h"
#include "MatchData.h"
#include "Classification.h"
#include "League.h"
#include "MatchData.h"
#include "TeamManager.h"
#include "ServiceProvider.h"
#include "LeagueManager.h"
#include "PeopleManager.h"
#include "LeagueCalendar.h"

void PrintMemberPlayerHeader(STD::ostream& o_stream)
{
	using namespace Utilities;

	o_stream << TabUpTo("ROLE", Team::NUM_TRAINERS_ROLES + 1);
	o_stream << TabUpTo("YS", 3);
	o_stream << TabUpTo("ATK", 4);
	o_stream << TabUpTo("DEF", 4);
	o_stream << TabUpTo("GLK", 4);
	o_stream << TabUpTo("RES", 4);
	o_stream << TabUpTo("STA", 4);
	o_stream << TabUpTo("AGG", 4);
	o_stream << TabUpTo("NM", 3);
	o_stream << TabUpTo("EVAL", 5);
	o_stream << TabUpTo("MM", 3);
	o_stream << TabUpTo("GL", 4);
	o_stream << TabUpTo("UN", 3);
	o_stream << TabUpTo("XP", 3);
	o_stream << TabUpTo("SAL", 5);
	o_stream << TabUpTo("SELL", 5);
	NOTDARIONLY(o_stream << TabUpTo("CONT", 5);)
	o_stream << TabUpTo("DIFF", 5);
	o_stream << STD::endl;
}

void PrintMemberPlayer(STD::ostream& o_stream, const People& i_player, const int i_role)
{
	using namespace Utilities;

	o_stream << TabUpTo(i_player.GetName(), People::GetParams().MAX_CHAR_NAME-1);
	char roleChar[NUM_FORMATION_ROLES+2] = "GDMA ";
	o_stream << TabUpTo(STL::string(1,roleChar[i_role]), Team::NUM_TRAINERS_ROLES+1);

	const int res = i_player.GetSkills().m_physicsSkills[Resistance];
	int sta = i_player.GetSkills().m_physicsSkills[Stamina] * 100;
	sta /= res;
	if(sta < 0) 
		sta = 0;

	o_stream << TabUpTo(i_player.GetHistory().GetAge(), 3);
	o_stream << TabUpTo(i_player.GetSkills().m_playerSkills[Attacker], 4);
	o_stream << TabUpTo(i_player.GetSkills().m_playerSkills[Defender], 4);
	o_stream << TabUpTo(i_player.GetSkills().m_playerSkills[Goalkeeper], 4);
	o_stream << TabUpTo(res, 4);
	o_stream << TabUpTo(sta, 4);
	o_stream << TabUpTo(i_player.GetSkills().m_mentalSkills[Aggressivity], 4);
	o_stream << TabUpTo(i_player.GetHistory().GetMatch(), 3);
	o_stream << TabUpTo(i_player.GetHistory().GetEvalStr(), 5);
	o_stream << TabUpTo(i_player.GetHistory().GetMoM(), 3);
	o_stream << TabUpTo(i_player.GetHistory().GetScoredGoal(), 4);
	o_stream << TabUpTo(i_player.GetAvailability().GetDaysBroken(), 3);
	o_stream << TabUpTo(i_player.GetAvailability().GetDaysExpulsion(), 3);
	o_stream << TabUpTo(i_player.GetSalary(), 5);
	o_stream << TabUpTo(i_player.SellValue(), 5);
	NOTDARIONLY(o_stream << TabUpTo(i_player.GetContract()->m_years, 5););
	o_stream << TabUpTo((i_player.GetHistory().GetYellowCard()%4 == 3) ? "YES" : "", 5);	
	o_stream << STD::endl;
}

void PrintMemberTrainerHeader(STD::ostream& o_stream)
{
	using namespace Utilities;

	o_stream << TabUpTo("GDAC", Team::NUM_TRAINERS_ROLES + 1);
	o_stream << TabUpTo("YS", 3);
	o_stream << TabUpTo("ATK", 4);
	o_stream << TabUpTo("DEF", 4);
	o_stream << TabUpTo("GLK", 4);
	o_stream << TabUpTo("INT", 4);
	o_stream << TabUpTo("AGG", 4);
	o_stream << TabUpTo("CHA", 4);
	o_stream << TabUpTo("SAL", 4);
	NOTDARIONLY(o_stream << TabUpTo("COT", 4);)
	o_stream << STD::endl;
}

void PrintMemberTrainer(STD::ostream& o_stream, const People& i_trainer, People* const * const i_roleList)
{
	using namespace Utilities;

	o_stream << TabUpTo(i_trainer.GetName(), People::GetParams().MAX_CHAR_NAME-1);

	for(int i=0; i<Team::NUM_TRAINERS_ROLES; ++i)
		o_stream << (((i_roleList[i]) == &i_trainer) ? '*' : ' ');
	o_stream << ' ';

	o_stream << TabUpTo(i_trainer.GetHistory().GetAge(), 3);
	o_stream << TabUpTo(i_trainer.GetSkills().m_trainerSkills[Attacker], 4);
	o_stream << TabUpTo(i_trainer.GetSkills().m_trainerSkills[Defender], 4);
	o_stream << TabUpTo(i_trainer.GetSkills().m_trainerSkills[Goalkeeper], 4);
	o_stream << TabUpTo(i_trainer.GetSkills().m_mentalSkills[Intelligence], 4);
	o_stream << TabUpTo(i_trainer.GetSkills().m_mentalSkills[Aggressivity], 4);
	o_stream << TabUpTo(i_trainer.GetSkills().m_mentalSkills[Charisma], 4);
	o_stream << TabUpTo(i_trainer.GetSalary(), 4);
	o_stream << STD::endl;
}

void PrintTeam(STD::ostream& o_stream, const Team& i_team)
{
	using namespace Utilities;

	typedef PeopleVecCit Iterator;
	size_t i = 1;
	o_stream << i_team.GetName() << STD::endl << STD::endl;
	o_stream << TabUpTo(" ", 4);
	o_stream << TabUpTo("TITOLARS: ", People::GetParams().MAX_CHAR_NAME -1);
	PrintMemberPlayerHeader(o_stream);

	int salarySum = 0;
	for(Iterator It = i_team.GetPlayersList().begin(); It != i_team.GetPlayersList().end(); ++It)
	{
		static const STL::string bracket = ")";
		o_stream << i << TabUpTo(bracket, (i>9 ? 2 : 3));
		PrintMemberPlayer(o_stream, *(*It), i_team.GetRoleByIndex(i-1));

		++i;
		if (i == Team::GetParams().TITOLARS_PLAYERS + 1) 
		{
			o_stream << STD::endl;
			o_stream << TabUpTo(" ", 4);
			o_stream << TabUpTo("PANCHINARS: ", People::GetParams().MAX_CHAR_NAME-1);
			PrintMemberPlayerHeader(o_stream);
		}
		salarySum += (*It)->GetSalary();
	}

	//print trainer

	o_stream << STD::endl;
	o_stream << TabUpTo(" ", 4);
	o_stream << TabUpTo("TRAINERS: ", People::GetParams().MAX_CHAR_NAME-1);
	PrintMemberTrainerHeader(o_stream);

	for(Iterator T_It = i_team.GetTrainersList().begin(); T_It != i_team.GetTrainersList().end(); ++T_It)
	{
		static const STL::string bracket = ")";
		o_stream << i << TabUpTo(bracket, (i>9 ? 2 : 3));
		PrintMemberTrainer(o_stream, *(*T_It), i_team.GetTrainersRoleList());

		salarySum += (*T_It)->GetSalary();
	}

	o_stream << STD::endl;
	o_stream << "Budget: " << TabUpTo(i_team.GetBudget(),8);
	o_stream << "Salary: " << TabUpTo(salarySum, 8);
	o_stream << "Bankrupts: " << TabUpTo(i_team.GetTeamHistory().GetBankruptCount(), 8);
	o_stream << "Warnings: " << TabUpTo(i_team.GetBankruptWarnings(), 2) << STD::endl;
}

void PrintMatchResult(STD::ostream& o_stream, const MatchData& i_match, ServiceProvider* const i_sp, const bool i_centered)
{
	static const int TEAM_NAME_SIZE = Team::GetParams().MAX_CHAR_TEAM_NAME;
	
	using namespace Utilities;

	const Team* const teamH = i_sp->GetTeamMgr().GetTeam(i_match.m_teamData[0].m_teamID);
	const Team* const teamA = i_sp->GetTeamMgr().GetTeam(i_match.m_teamData[1].m_teamID);

	if(i_centered)
	{
		o_stream 
			<< STL::string( (Consts::SCREEN_WIDTH / 2 - 5) - teamH->GetName().length() , ' ')
			<< teamH->GetName() << "  "
			<< i_match.m_teamData[0].m_goals << "-"
			<< i_match.m_teamData[1].m_goals << "  "
			<< teamA->GetName();
	}
	else
	{
		o_stream << TabUpTo(teamH->GetName(), TEAM_NAME_SIZE) << " - ";
		o_stream << TabUpTo(teamA->GetName(), TEAM_NAME_SIZE) << "   ";
		o_stream << TabUpTo(i_match.m_teamData[0].m_goals, 2) << " - ";
		o_stream << TabUpTo(i_match.m_teamData[1].m_goals, 2) << "   ";
	}
}

void PrintMatchData(STD::ostream& o_stream, const MatchData& i_match, ServiceProvider* const i_sp)
{
	static const char* s_cards[] = {"      ", " [Y]  ", " [YY] ", " [R]  ", " [YR] ", " [RR] "};

	PrintMatchResult(o_stream, i_match, i_sp, false);
	o_stream << STD::endl << STD::endl;

	for(int j=0; j<2; ++j)
	{
		const Team* const team = i_sp->GetTeamMgr().GetTeam(i_match.m_teamData[j].m_teamID);

		o_stream << "Team: " << team->GetName() << STD::endl;
		for(int i=0; i<static_cast<int>(Team::GetParams().TITOLARS_PLAYERS); ++i)
		{
			const People* const player = i_sp->GetPeopleMgr().GetPeopleFromID(i_match.m_teamData[j].m_playerData[i].m_playerID);
			o_stream << EvalToStr(i_match.m_teamData[j].m_playerData[i].m_evaluation);
			o_stream << s_cards[STL::min(5, i_match.m_teamData[j].m_playerData[i].m_cards)];
			o_stream << player->GetName().c_str();
			if(i_match.m_teamData[j].m_playerData[i].m_goals != 0)
				o_stream << " (" << i_match.m_teamData[j].m_playerData[i].m_goals << ")";
			if(j == i_match.m_teamMOM && i == i_match.m_playerMOM)
				o_stream << "  ***Man Of The Match***";
			o_stream << STD::endl;
		}
		o_stream << STD::endl;
	}
	o_stream << STD::endl;
}

void PrintMatchEvents(STD::ostream& o_stream, const MatchData& i_match)
{
	for (EventCollection::const_iterator ev = i_match.m_events.begin(); ev != i_match.m_events.end(); ++ev)
		o_stream << (*ev).minute << " " << (*ev).message << "\n";
	o_stream << STD::endl;
}

void PrintPostMatchEvents(STD::ostream& o_stream, const MatchData& i_match, ServiceProvider* const i_sp)
{
	for(int j=0; j<2; ++j)
	{
		const Team* const team = i_sp->GetTeamMgr().GetTeam(i_match.m_teamData[j].m_teamID);
		const PeopleVec& playerList = team->GetPlayersList();
		for (size_t i = 0; i < Team::GetParams().TITOLARS_PLAYERS; ++i)
		{
			if (playerList[i]->GetAvailability().IsBroken())
			{
				o_stream <<" ! " << team->GetName() << ": " + playerList[i]->GetName();
				o_stream << " infortunato per " << playerList[i]->GetAvailability().GetDaysBroken() << " giornate." << STD::endl;
			}

			if (playerList[i]->GetAvailability().IsExpulse())
			{
				o_stream <<" ! " << team->GetName() << ": " + playerList[i]->GetName();
				o_stream << " espulso per " << playerList[i]->GetAvailability().GetDaysExpulsion() << " giornate." << STD::endl;
			}
		}
	}
}

STL::string& LeaguePositionToSymbol(const League& i_league, const int i_pos)
{
	static STL::string promoted = "+";
	static STL::string demoted = "-";
	static STL::string none = " ";
	const int numPromoted = i_league.GetNumPromoted();
	const int numDemoted = i_league.GetNumDemoted();
	if(i_pos < numPromoted)
		return promoted;
	if(i_pos >= static_cast<int>(i_league.GetTeams().size()) - numDemoted)
		return demoted;
	return none;
}

void PrintClassification(STD::ostream& o_stream, const League& i_league, ServiceProvider* const i_sp)
{
	using namespace Utilities;
	const size_t max_char_team_name = Team::GetParams().MAX_CHAR_TEAM_NAME;
	const Classification& classification = *i_league.GetClassification();

	STL::string title = "TEAM:";
	o_stream << TabUpTo("INDEX",6);
	o_stream << TabUpTo("TEAM", max_char_team_name);
	o_stream << TabUpTo("X", 2);
	o_stream << TabUpTo("PTS", 4);
	o_stream << TabUpTo("G", 3);
	o_stream << TabUpTo("W", 3);
	o_stream << TabUpTo("D", 3);
	o_stream << TabUpTo("L", 3);
	o_stream << TabUpTo("GO", 4);
	o_stream << TabUpTo("GI", 4);
	o_stream << TabUpTo("GD", 5);
	o_stream << STD::endl;
	Print::PrintDecorationLine(o_stream, '-');
	o_stream << STD::endl;

	const TeamScoreCollection& teamScores = classification.GetTeamScores();

	for(size_t i = 0; i < teamScores.size(); ++i)
	{
		const TeamScore& teamScore = teamScores.at(i);
		const int goalDifference = teamScore.m_outGoals - teamScore.m_inGoals;
		const int playedMatches = teamScore.m_winMatches + teamScore.m_drawMathes + teamScore.m_lostMatches;
		const Team* const team = i_sp->GetTeamMgr().GetTeam(teamScore.m_teamID);

		o_stream << TabUpTo(teamScore.m_teamID+1, 4);
		o_stream << (team->IsUserControlled() ? "* " : "  ");
		o_stream << TabUpTo(team->GetName(), max_char_team_name);
		o_stream << TabUpTo(LeaguePositionToSymbol(i_league, i), 2);
		o_stream << TabUpTo(teamScore.m_score, 4);
		o_stream << TabUpTo(playedMatches, 3);
		o_stream << TabUpTo(teamScore.m_winMatches, 3);
		o_stream << TabUpTo(teamScore.m_drawMathes, 3);
		o_stream << TabUpTo(teamScore.m_lostMatches, 3);
		o_stream << TabUpTo(teamScore.m_outGoals, 4);
		o_stream << TabUpTo(teamScore.m_inGoals, 4);
		o_stream << TabUpTo(goalDifference, 5);
		o_stream << STD::endl;
	}
	o_stream << STD::endl;
}

void PrintCalendar(STD::ostream & o_stream, const Team& i_team, ServiceProvider* const i_sp)
{
	static char s_win[4]  = "###";
	static char s_draw[4] = "  #";

	const League& league = *i_sp->GetLeagueMgr().GetLeagueFromID(i_team.GetLeagueID());
	const LeagueCalendar& calendar = *league.GetCalendar();
	const TeamVec& teams = calendar.GetTeamList();
	const int teamID = i_team.GetID();

	typedef TurnGenerator::Couples::const_iterator Iterator;
	TurnGenerator::Couples turn;

	int count = 0;
	for(size_t i = 0; i < (2 * (teams.size() -1)); ++i)
	{
		if(i < league.GetCalendar()->GetTurnNumber())
		{
			const MatchDataVec& scores = league.GetClassification()->GetMatchesHistory();
			MatchDataVecCIt beg = scores.begin() + teams.size()/2 * i;
			MatchDataVecCIt end = beg + teams.size()/2;
			for(MatchDataVecCIt it = beg; it != end; ++it)
			{
				const MatchData& match = *(*it);
				if(match.IsPlayingTeam(teamID))
				{
					o_stream << Utilities::TabUpTo(++count,5);
					PrintMatchResult(o_stream, match, i_sp, false);

					if(match.m_teamData[0].m_goals == match.m_teamData[1].m_goals)
					{
						o_stream << s_draw;
					}
					else if ((match.m_teamData[0].m_teamID == teamID) && (match.m_teamData[0].m_goals > match.m_teamData[1].m_goals) ||
							(match.m_teamData[1].m_teamID == teamID) && (match.m_teamData[0].m_goals < match.m_teamData[1].m_goals))
					{
						o_stream << s_win;
					}
					o_stream << STD::endl;
					break;
				}
			}
		}
		else
		{
			calendar.GetTurnGenerator().GetTurnNumber(i, turn);
			
			for(Iterator It = turn.begin(); It != turn.end(); ++It)
			{
				if(teams[It->first]->GetID() == i_team.GetID() || teams[It->second]->GetID() == i_team.GetID())
				{
					o_stream << Utilities::TabUpTo(++count,5);
					o_stream << Utilities::TabUpTo(teams.at(It->first)->GetName(), Team::GetParams().MAX_CHAR_TEAM_NAME)
							<< " - "
							<< Utilities::TabUpTo(teams.at(It->second)->GetName(), Team::GetParams().MAX_CHAR_TEAM_NAME)
							<< STD::endl;
					break;
				}
			}
		}
	}
	o_stream << STD::endl;
}

void PrintCalendar(STD::ostream & o_stream, const League& i_league, ServiceProvider* const i_sp)
{
	typedef TurnGenerator::Couples::const_iterator Iterator;
	
	const LeagueCalendar& calendar = *i_league.GetCalendar();
	const TeamVec& teams = calendar.GetTeamList();

	TurnGenerator::Couples turn;

	for(size_t i = 0; i < (2 * (teams.size() -1)); ++i)
	{
		o_stream << STD::endl << "Giornata " << i+1 << ":" << STD::endl;

		if(i < i_league.GetCalendar()->GetTurnNumber())
		{
			const MatchDataVec& scores = i_league.GetClassification()->GetMatchesHistory();
			MatchDataVecCIt beg = scores.begin() + teams.size()/2 * i;
			MatchDataVecCIt end = beg + teams.size()/2;
			for(MatchDataVecCIt it = beg; it != end; ++it)
			{
				PrintMatchResult(o_stream, *(*it), i_sp, true);
				o_stream << STD::endl;
			}
		}
		else
		{
			calendar.GetTurnGenerator().GetTurnNumber(i, turn);
			
			for(Iterator It = turn.begin(); It != turn.end(); ++It)
			{
				STL::string firstUserControlled = (teams.at(It->first)->IsUserControlled()) ? "*** " : "";
				STL::string secondUserControlled = (teams.at(It->second)->IsUserControlled()) ? "*** " : "";
				o_stream	<< Print::CenterToLeft(firstUserControlled + teams.at(It->first)->GetName() + " -" );
				o_stream	<< " "
							<< secondUserControlled + teams.at(It->second)->GetName() 
							<< STD::endl;
			}
		}
	}
	o_stream << STD::endl;
}

const STL::string& GetTeamName(const People& i_player, const STL::string& i_teamName)
{
	static STL::string RetiredTeamName;
	if(!i_player.IsRetired())
		return i_teamName;

	RetiredTeamName = "--"; 
	RetiredTeamName += Utilities::IntToString(i_player.GetHistory().GetRetirementYear(StatusPlayer));
	RetiredTeamName += "--";
	return RetiredTeamName;
}
